package com.ellwood.copyright.common.core.utils.excel;

import com.ellwood.copyright.common.core.annotation.ExcelFieldConverter;
import com.ellwood.copyright.common.core.annotation.ExcelHeader;
import com.ellwood.copyright.common.core.constant.FieldConverter;
import com.ellwood.copyright.common.core.enums.EnumConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @ProjectName: ell-copyright-pro
 * @PackageName: com.ellwood.copyright.common.core.utils.excel
 * @ClassName: ExcelImportUtil
 * @Description: // 导入Excel
 * @Author: Ellwood
 * @CreateDate: 2024/12/23 - 14:25
 * @Version: V1.0.0
 */
@Slf4j
public class ExcelImportUtil {

    // 用于格式化单元格
    private static DataFormatter dataFormatter = new DataFormatter();

    /**
     * 导入Excel工具函数
     * @param file Excel文件
     * @param clazz 实体类类型
     * @param <T> 实体
     * @return 返回导入的数据列表
     * @throws Exception 异常
     */
    public static <T> List<T> importFromExcel(MultipartFile file, Class<T> clazz) throws Exception {
        InputStream is=file.getInputStream();
        Workbook workbook = new XSSFWorkbook(is);// 使用XSSFWorkbook读取Excel文件
        Sheet sheet = workbook.getSheetAt(0);// 获取第一个sheet

        Iterator<Row> rowIterator = sheet.iterator();
        rowIterator.next();// 跳过标题行

        List<T> dataList=new ArrayList<>();
        while (rowIterator.hasNext()) {
            Row row = rowIterator.next();
            // 创建实例
            T data=clazz.getDeclaredConstructor().newInstance();

            // 填充数据
            int cellIndex=0;
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                // 判断字段是否有ExcelHeader注解
                if (field.isAnnotationPresent(ExcelHeader.class)) {
                    field.setAccessible(true);

                    try{
                        // 获取单元格的值
                        Object value = getCellValue(row, cellIndex++,field);

                        // 判断是否是日期类型，如果是，进行格式化
                        /*if (value instanceof Date) {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                            value = sdf.format((Date) value);
                        }*/

                        // 使用转换器注解来处理字段的转换
                        if (field.isAnnotationPresent(ExcelFieldConverter.class)) {
                            ExcelFieldConverter converterAnnotation = field.getAnnotation(ExcelFieldConverter.class);
                            // 获取对应的EnumConverter
                            FieldConverter converter = converterAnnotation.converter()
                                    .getConstructor(EnumConverter.class)
                                    .newInstance(getEnumForField(field.getName()));// 获取对应的EnumConverter

                            // 执行转换
                            value = converter.convert(value);
                        }

                        // 设置字段值
                        field.set(data, value);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
            dataList.add(data);
        }
        workbook.close();
        return dataList;
    }

    /**
     * 根据字段名称动态获取枚举类型
     * @param fieldName 字段名称
     * @return 返回对应的EnumConverter
     */
    private static EnumConverter getEnumForField(String fieldName) {
        if ("gender".equals(fieldName)) {
            return EnumConverter.GENDER;
        } else if ("isState".equals(fieldName)) {
            return EnumConverter.STATUS;
        }

        return null;
    }

    /**
     * 根据单元格类型获取数据
     * @param row 行
     * @param cellIndex 列索引
     * @return 返回单元格的值
     */
    private static Object getCellValue(Row row, int cellIndex, Field field) {
        Cell cell = row.getCell(cellIndex);
        if (cell == null) return null;

        // 获取字段名称
        String fieldName=field.getName();

        // 如果字段是需要作为字符串处理的字段，如 phone, email, idCard 等
        if (isStringField(fieldName)) {
            // 使用 DataFormatter 读取单元格值，确保读取为字符串
            return dataFormatter.formatCellValue(cell); // 返回格式化后的值
        }

        switch (cell.getCellType()) {
            case STRING:
                String stringValue=cell.getStringCellValue().trim();

                // 判断字段类型并转换
                if (field.getType()==Integer.class) {
                    if (field.getName().equals("gender")) {
                        return new FieldConverterUtil(EnumConverter.GENDER).convert(stringValue);
                    }else if (field.getName().equals("isState")) {
                        return new FieldConverterUtil(EnumConverter.STATUS).convert(stringValue);
                    }
                }

                // 如果是string类型的日期值，讲起转换为Date
                if (field.getType()== Date.class) {
                    return parseDate(stringValue);
                }

                // 根据字段类型转换
                if (field.getType()== Long.class||field.getType()==long.class) {
                    return parseLong(stringValue);
                }else if (field.getType()== Integer.class||field.getType()==int.class) {
                    return parseInt(stringValue);
                }else if (field.getType()== Double.class||field.getType()==double.class) {
                    return parseDouble(stringValue);
                }else{
                    return stringValue;  // 其他情况返回字符串
                }
            case NUMERIC:
                // 使用 DataFormatter 读取格式化后的字符串
                String numericValue=dataFormatter.formatCellValue(cell); // 返回格式化后的值

                // 如果是日期类型，处理Date
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue();
                }

                // 根据字段类型转换
                if (field.getType() == Long.class || field.getType() == long.class) {
                    return parseLong(numericValue);
                } else if (field.getType() == Integer.class || field.getType() == int.class) {
                    return parseInt(numericValue);
                } else if (field.getType() == Double.class || field.getType() == double.class) {
                    return parseDouble(numericValue);
                } else {
                    return numericValue; // 返回字符串
                }

            case BOOLEAN:
                return cell.getBooleanCellValue();
            default:
                return null;
        }
    }

    /**
     * 解析想字符串日期格式为Date
     * @param value 字符串日期
     * @return 转换后Date值
     */
    private static Date parseDate(String value) {
        try{
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            return value != null && !value.isEmpty() ? sdf.parse(value) : null;
        }catch (ParseException e){
            log.error("Date类型解析失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析Long类型的值
     * @param value 字符串值
     * @return 转换后的Long的值
     */
    private static Long parseLong(String value) {
        try{
            return value != null && !value.isEmpty() ? Long.parseLong(value) : null;
        }catch (NumberFormatException e){
            log.error("Long类型解析失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析Integer类型的值
     * @param value 字符串值
     * @return 转换后的Integer值
     */
    private static Integer parseInt(String value) {
        try {
            return value != null && !value.isEmpty() ? Integer.parseInt(value) : null;
        } catch (NumberFormatException e) {
            log.error("Integer类型解析失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 解析Double类型的值
     * @param value 字符串值
     * @return 转换后的Double值
     */
    private static Double parseDouble(String value) {
        try {
            return value != null && !value.isEmpty() ? Double.parseDouble(value) : null;
        } catch (NumberFormatException e) {
            log.error("Double类型解析失败：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 判断字段是否需要作为字符串类型处理
     * @param fieldName 字段名称
     * @return 是否为字符串字段
     */
    public static boolean isStringField(String fieldName) {
        // 定义一个字段列表，所有需要作为String类型处理的字段
        List<String> stringFields = Arrays.asList("phone", "email", "idCard", "postalCode", "address");

        // 如果字段在列表中，返回true，表示该字段需要作为字符串处理
        return stringFields.contains(fieldName);
    }

}
